package com.yfp.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.hy.corecode.idgen.WFGIdGenerator;
import com.yfp.common.core.domain.ResponseEnum;
import com.yfp.common.core.exception.ServiceException;
import com.yfp.common.core.utils.PageUtils;
import com.yfp.common.core.web.page.TableDataInfo;
import com.yfp.common.datascope.annotation.DataScope;
import com.yfp.common.security.utils.SecurityUtils;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.enums.CouponStatus;
import com.yfp.operation.mapper.MarCouponPackMapper;
import com.yfp.operation.mapper.MarketingMapper;
import com.yfp.operation.service.*;
import com.yfp.system.api.domain.SysUser;
import com.yfp.operation.domain.*;
import com.yfp.operation.domain.dto.*;
import com.yfp.operation.domain.vo.*;
import com.yfp.operation.service.*;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 *
 * @description 针对表【mar_coupon_pack(优惠券礼包)】的数据库操作Service实现
 * @createDate 2024-09-25 10:37:51
 */
@Service
public class MarCouponPackServiceImpl extends ServiceImpl<MarCouponPackMapper, MarCouponPack> implements MarCouponPackService {

    @Resource
    private WFGIdGenerator wfgIdGenerator;
    @Resource
    private MiniBannerService miniBannerService;
    @Resource
    private MarCouponPackMapper marCouponPackMapper;
    @Resource
    private MarCouponPackDetailsService marCouponPackDetailsService;
    @Resource
    private ClientCouponService clientCouponService;
    @Resource
    private MarCouponService marCouponService;
    @Resource
    private MarketingMapper marketingMapper;
    @Resource
    private ClientService clientService;
    @Resource
    private MarCouponPackShopService marCouponPackShopService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createCouponPack(MarCouponPackDTO marCouponPackDTO) {
        SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
        Long userId = sysUser.getUserId();

        DateTime date = DateUtil.date();
        MarCouponPack marCouponPack = BeanUtil.toBean(marCouponPackDTO, MarCouponPack.class);
        List<MarCouponPackDetailsDTO> marCouponPackDetailsDTOS = marCouponPackDTO.getMarCouponPackDetails();
        List<MarCouponPackDetails> marCouponPackDetails = BeanUtil.copyToList(marCouponPackDetailsDTOS, MarCouponPackDetails.class);

        // 校验 礼包内容是否非空
        if (CollUtil.isEmpty(marCouponPackDetails)) {
            throw new ServiceException("礼包内容不能为空");
        }
        // 校验 礼包内容是否有 1进行中，4待开始之外的券状态。状态[0删除、1进行中、2已失效、3已过期、4待开始]
        List<MarCoupon> marCoupons = marCouponService.listByIds(marCouponPackDetailsDTOS.stream().map(MarCouponPackDetailsDTO::getCouponId).collect(Collectors.toList()));
        Map<Long, MarCoupon> marCouponMapById = marCoupons.stream().collect(Collectors.toMap(MarCoupon::getId, Function.identity()));
        List<MarCouponPackDetailsDTO> isErrorStatusList = marCouponPackDetailsDTOS.stream().filter(item -> {
            MarCoupon marCoupon = marCouponMapById.getOrDefault(item.getCouponId(), null);
            return Objects.isNull(marCoupon) || CollUtil.safeContains(Arrays.asList(0, 2, 3), marCoupon.getStatus());
        }).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(isErrorStatusList)) {
            List<Long> errorMarCoupons = isErrorStatusList.stream().map(MarCouponPackDetailsDTO::getCouponId).collect(Collectors.toList());
            throw new ServiceException(ResponseEnum.INVALID_PACKAGE.getMsg(), ResponseEnum.INVALID_PACKAGE.getCode(), errorMarCoupons);
        }
        // 校验 赠券数一定小于等于每人限领次数，最小为1，最大为每人可领取次数
        List<MarCoupon> isErrorCountList = marCouponPackDetailsDTOS.stream().filter(item -> {
            MarCoupon marCoupon = marCouponMapById.getOrDefault(item.getCouponId(), new MarCoupon());
            return !NumberUtil.isIn(NumberUtil.toBigDecimal(item.getCouponCount()), BigDecimal.ONE, NumberUtil.toBigDecimal(marCoupon.getReceiveCount()));
        }).map(item -> marCouponMapById.getOrDefault(item.getCouponId(), new MarCoupon())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(isErrorCountList)) {
            String isErrorCountCouponNameList = isErrorCountList.stream().map(MarCoupon::getCouponName).collect(Collectors.joining(","));
            throw new ServiceException(String.format("[%s]赠券数需要小于等于每人限领次数", isErrorCountCouponNameList));
        }

        // 设备基本数据
        marCouponPack.setCreateTime(date);
        marCouponPack.setCreateUserId(userId);
        marCouponPack.setMarketingId(wfgIdGenerator.next());
        marCouponPack.setSurplusCount(marCouponPack.getCount());
        // 检测状态 状态:[1:进行中,2:已失效]
        Integer status = this.checkStatus(marCouponPack.getFailureCondition(), marCouponPackDetailsDTOS);
        marCouponPack.setStatus(status);
        marCouponPack.setDeptId(sysUser.getDeptId());
        // 添加营销活动
        Marketing marketing = new Marketing();
        marketing.setType(3);
        marketing.setId(marCouponPack.getMarketingId());

        // 保存礼包数据
        marCouponPackMapper.insert(marCouponPack);
        marCouponPackDetails.forEach(item -> item.setCouponPackId(marCouponPack.getId()));
        marCouponPackDetailsService.saveBatch(marCouponPackDetails);
        marketing.setMarCouponPackId(marCouponPack.getId());
        marketingMapper.add(marketing);

        // 判断是否弹窗，如果弹窗则需要将之前的弹窗banner覆盖
        if (marCouponPack.getPopup().equals(CouponStatus.ONE.getStatus())) {
            MiniBanner miniBanner = new MiniBanner();
            miniBanner.setName(marCouponPack.getPackName());
            miniBanner.setImg(marCouponPack.getPopupUrl());
            miniBanner.setPosition(3);
            miniBanner.setMarketingId(marCouponPack.getMarketingId());
            miniBanner.setRemark("添加券时加入");
            miniBanner.setCityName(marCouponPack.getCityName());
            miniBanner.setDeptId(marCouponPack.getDeptId());
            miniBannerService.createMiniBannerPopup(miniBanner);
        }
    }
    @Override
    @DataScope(deptAlias = "mcp")
    public TableDataInfo<MarCouponPackVO> listCouponPack(MarCouponPackReqDTO marCouponPackReqDTO) {
        PageUtils.startPage();
        List<MarCouponPack> marCouponPacks = marCouponPackMapper.selectListByReq(marCouponPackReqDTO);
        long total = new PageInfo(marCouponPacks).getTotal();

        // 统计礼包内容数量
        List<Long> couponPackIds = marCouponPacks.stream().map(MarCouponPack::getId).collect(Collectors.toList());
        List<MarCouponPackCountDTO> couponPackDetailCountDTOS = marCouponPackDetailsService.countByCouponPackIds(couponPackIds);
        // 展示不上，还用上面的
        // List<MarCouponPackCountDTO> couponPackDetailCountDTOS = marCouponPackDetailsService.countMarCouponByCouponPackIds(couponPackIds);
        Map<Long, Long> couponPackDetailsCountById = couponPackDetailCountDTOS.stream().collect(Collectors.toMap(MarCouponPackCountDTO::getCouponPackId, MarCouponPackCountDTO::getCount));

        // 填充礼包内容数量、已领取数量
        List<MarCouponPackVO> marCouponPackVOS = marCouponPacks.stream().map(item -> {
            MarCouponPackVO couponPackVO = BeanUtil.toBean(item, MarCouponPackVO.class);

            Long couponCount = couponPackDetailsCountById.getOrDefault(item.getId(), 0L);
            couponPackVO.setCouponCount(couponCount);
            couponPackVO.setReceiveCount(item.getCount() - item.getSurplusCount());
            return couponPackVO;
        }).collect(Collectors.toList());

        TableDataInfo<MarCouponPackVO> dataTable = PageUtils.getDataTable(marCouponPackVOS);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public MarCouponPackInfoVO getCouponPackById(Long id) {
        MarCouponPack marCouponPack = marCouponPackMapper.selectById(id);
        List<MarCouponPackDetails> marCouponPackDetails = marCouponPackDetailsService.listByCouponPackId(id);

        // 转变为前端展示数据格式
        List<MarCouponPackDetailVO> couponPackDetailVOS = marCouponPackDetailsService.complementListData(marCouponPackDetails);
        MarCouponPackInfoVO marCouponPackInfoVO = BeanUtil.toBean(marCouponPack, MarCouponPackInfoVO.class);
        marCouponPackInfoVO.setMarCouponPackDetails(couponPackDetailVOS);
        return marCouponPackInfoVO;
    }

    @Override
    public MarCouponPack findById(Long id) {
        return marCouponPackMapper.findById(id);
    }

    @Override
    public List<MarCouponPack> findByIds(List<Long> ids) {
        if (CollUtil.isEmpty(ids)){
            return List.of();
        }
        return this.listByIds(ids);
    }

    @Override
    public void updateStatusById(MarCouponPackUpdateStatusReqDTO couponPackUpdateStatusReqDTO) {
        marCouponPackMapper.updateStatusById(couponPackUpdateStatusReqDTO.getId(), couponPackUpdateStatusReqDTO.getStatus());
        if (CollUtil.containsAny(Arrays.asList(couponPackUpdateStatusReqDTO.getStatus()), Arrays.asList(1, 2))) {
            // 同步更新礼包虚拟商品列表状态
            List<MarCouponPackShop> marCouponPackShops = marCouponPackShopService.findByPackIds(Collections.singletonList(couponPackUpdateStatusReqDTO.getId()));
            marCouponPackShops = marCouponPackShops.stream().filter(item -> 1 == item.getStatus()).collect(Collectors.toList());
            List<Long> packShopIds = marCouponPackShops.stream().map(MarCouponPackShop::getId).collect(Collectors.toList());
            marCouponPackShopService.updateStatusByIds(packShopIds, 2);
        }
    }

    @Override
    public void updateStatusByIds(List<Long> invalidMarCouponPackIds, Integer status) {
        if (CollUtil.isEmpty(invalidMarCouponPackIds)) {
            return;
        }
        marCouponPackMapper.updateStatusByIds(invalidMarCouponPackIds, status);
    }

    @Override
    public TableDataInfo<MarCouponPackDetailVO> listPackDetailById(Long couponPackId) {
        PageUtils.startPage();
        List<MarCouponPackDetails> marCouponPackDetails = marCouponPackDetailsService.listByCouponPackId(couponPackId);
        long total = new PageInfo(marCouponPackDetails).getTotal();
        // 转变为前端展示数据格式
        List<MarCouponPackDetailVO> couponPackDetailVOS = marCouponPackDetailsService.complementListData(marCouponPackDetails);

        TableDataInfo<MarCouponPackDetailVO> dataTable = PageUtils.getDataTable(couponPackDetailVOS);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public TableDataInfo<MarCouponPackReceiveUserVO> listReceiveUserByReq(MarCouponPackReceiveUserReqDTO receiveUserReqDTO) {
        PageUtils.startPage();
        List<Client> clients = clientService.listByReceiveUserReq(receiveUserReqDTO);
        long total = new PageInfo(clients).getTotal();

        List<String> clientIds = clients.stream().map(Client::getId).collect(Collectors.toList());
        List<ClientCoupon> clientCouponList = clientCouponService.listByCouponPackIdAndClientIds(receiveUserReqDTO.getId(), clientIds);
        Map<String, List<ClientCoupon>> clientCouponMapByClientId = clientCouponList.stream().collect(Collectors.groupingBy(ClientCoupon::getClientId));

        List<MarCouponPackReceiveUserVO> receiveUserVOS = clients.stream().map(item -> {
            List<ClientCoupon> clientCoupons = clientCouponMapByClientId.getOrDefault(item.getId(), Collections.emptyList());

            MarCouponPackReceiveUserVO marCouponPackReceiveUserVO = new MarCouponPackReceiveUserVO();
            marCouponPackReceiveUserVO.setClientName(item.getNickName());
            marCouponPackReceiveUserVO.setReceiveTime(CollUtil.getFirst(clientCoupons).getCreateTime());
            marCouponPackReceiveUserVO.setCount(clientCoupons.size());
            return marCouponPackReceiveUserVO;
        }).collect(Collectors.toList());

        TableDataInfo<MarCouponPackReceiveUserVO> dataTable = PageUtils.getDataTable(receiveUserVOS);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public TableDataInfo<MarCouponPackCouponVO> listCouponByReq(MarCouponPackCouponReqDTO marCouponPackCouponReqDTO) {
        // 只筛选状态[1进行中、4待开始]
        marCouponPackCouponReqDTO.setStatusList(Arrays.asList(1, 4));
        PageUtils.startPage();
        List<MarCoupon> marCoupons = marCouponService.listByPackCouponReq(marCouponPackCouponReqDTO);
        long total = new PageInfo(marCoupons).getTotal();
        List<MarCouponPackCouponVO> marCouponPackCouponVOS = BeanUtil.copyToList(marCoupons, MarCouponPackCouponVO.class);

        TableDataInfo<MarCouponPackCouponVO> dataTable = PageUtils.getDataTable(marCouponPackCouponVOS);
        dataTable.setTotal(total);
        return dataTable;
    }

    @Override
    public Integer checkStatus(Integer failureCondition, List<MarCouponPackDetailsDTO> couponPackDetailsDTOS) {
        if (CollUtil.isEmpty(couponPackDetailsDTOS)) {
            return 2;
        }
        List<Long> couponIdList = couponPackDetailsDTOS.stream().map(MarCouponPackDetailsDTO::getCouponId).distinct().collect(Collectors.toList());
        List<MarCoupon> marCoupons = marCouponService.listByIds(couponIdList);
        Map<Long, MarCoupon> marCouponMapById = marCoupons.stream().collect(Collectors.toMap(MarCoupon::getId, Function.identity()));

        // 失效的数量
        long count = couponPackDetailsDTOS.stream().filter(item -> {
            MarCoupon marCoupon = marCouponMapById.getOrDefault(item.getCouponId(), new MarCoupon());
            // 判断库存,库存不足
            boolean less = NumberUtil.isLess(NumberUtil.toBigDecimal(marCoupon.getSurplusCount()), NumberUtil.toBigDecimal(item.getCouponCount()));
            // 判断状态,失效状态[0删除、1进行中、2失效、3已过期、4待开始]
            boolean contains = CollUtil.contains(Arrays.asList(0, 2, 3), marCoupon.getStatus());
            return less || contains;
        }).count();

        // 礼包失效条件：1：所有优惠券库存不足或失效时礼包失效、0：任意一张优惠券库存不足或失效时礼包失效
        if (failureCondition == 1) {
            // 所有优惠券库存不足或失效时礼包失效
            return count == couponPackDetailsDTOS.size() ? 2 : 1;
        } else if (failureCondition == 0) {
            // 任意一张优惠券库存不足或失效时礼包失效
            return count > 0 ? 2 : 1;
        }
        // return:[1:进行中,2:已失效]
        return 2;
    }

    @Override
    public void checkAndUpdateAllStatus() {
        MarCouponPackReqDTO marCouponPackReqDTO = new MarCouponPackReqDTO();
        marCouponPackReqDTO.setStatus(1);
        List<MarCouponPack> marCouponPacks = marCouponPackMapper.selectListByReq(marCouponPackReqDTO);
        List<Long> couponPackId = marCouponPacks.stream().map(item -> item.getId()).collect(Collectors.toList());
        List<MarCouponPackDetails> marCouponPackDetails = marCouponPackDetailsService.listByCouponPackIds(couponPackId);
        Map<Long, List<MarCouponPackDetails>> packDetailsMapByCouponPackId = marCouponPackDetails.stream().collect(Collectors.groupingBy(MarCouponPackDetails::getCouponPackId));

        // 失效的礼包列表
        List<Long> invalidMarCouponPackIds = marCouponPacks.stream().peek(item -> {
            List<MarCouponPackDetails> couponPackDetails = packDetailsMapByCouponPackId.getOrDefault(item.getId(), new ArrayList<>());
            List<MarCouponPackDetailsDTO> marCouponPackDetailsDTOS = BeanUtil.copyToList(couponPackDetails, MarCouponPackDetailsDTO.class);

            // 检测状态 状态:[1:进行中,2:已失效]
            Integer status = this.checkStatus(item.getFailureCondition(), marCouponPackDetailsDTOS);
            item.setStatus(status);
        }).filter(item -> item.getStatus() == 2).map(MarCouponPack::getId).collect(Collectors.toList());

        // 更新礼包状态
        this.updateStatusByIds(invalidMarCouponPackIds, 2);

        // 同步更新礼包虚拟商品列表状态
        List<MarCouponPackShop> marCouponPackShops = marCouponPackShopService.findByPackIds(invalidMarCouponPackIds);
        marCouponPackShops = marCouponPackShops.stream().filter(item -> 1 == item.getStatus()).collect(Collectors.toList());
        List<Long> packShopIds = marCouponPackShops.stream().map(MarCouponPackShop::getId).collect(Collectors.toList());
        marCouponPackShopService.updateStatusByIds(packShopIds, 2);
    }

    @Override
    public void updateSurplusCount(Long id, long l) {
        marCouponPackMapper.updateSurplusCount(id,l);
    }

}




